#include "picture.h"
#include <unistd.h>
#include <dirent.h>
#include <map>
#include <mutex>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "BitImage.h"
#include "JpegImage.h"
#include "PngImage.h"

static int thread_func(Picture *obj);
static int search_image(std::string &path, int list_max);
static void update_page_img_list(int page);
static unsigned char *bmp_image_decode(std::string &file, int &wight, int &height, int &pit_per_pixel);
static unsigned char *jpeg_image_decode(std::string &file, int &wight, int &height, int &pit_per_pixel);
static unsigned char *png_image_decode(std::string &file, int &wight, int &height, int &pit_per_pixel);
static void get_image(int tag, ImgInfo *info);
static int get_next_tag(int now_tag);
static int get_prev_tag(int now_tag);
static void change_img_list_page(int page);

static std::map<int, std::string> imageTable; // 图像映射表
static std::mutex update_mutex;
static std::mutex *ui_mutex = nullptr;
static int dest_page = 1; // 目标页面

Picture::Picture(void (*exit_cb)(lv_event_t *), std::mutex &uiMutex)
{
    thread_exit_flag = false;
    ui_mutex = &uiMutex;

    gui_opt_t gui_opts;

    gui_opts.exit_cb = exit_cb;
    gui_opts.get_image = get_image;
    gui_opts.get_next_tag = get_next_tag;
    gui_opts.get_prev_tag = get_prev_tag;
    gui_opts.change_list_page = change_img_list_page;

    picture_gui_init(&gui_opts);

    pthread = new std::thread(thread_func, this);
}

Picture::~Picture()
{
    thread_exit_flag = true;
    pthread->join();
    delete pthread;

    picture_gui_release();
}

static int thread_func(Picture *obj)
{
    usleep(50000);

    std::string image_path = "/overlay/images/";

    int img_total = search_image(image_path, 300);
    picture_gui_set_img_list_page(img_total);

    printf("search image complete! total:%d\n", img_total);

    while (!obj->getExitFlag())
    {
        if(update_mutex.try_lock() == true)
        {
            update_page_img_list(dest_page);
            picture_gui_set_list_change_over();
        }
        
        usleep(10000);
    }

    return 0;
}

static int search_image(std::string &path, int list_max)
{
    int cnt_r = 0;
    int i;
    bool legal_img = false;
    std::string file_path;

    struct dirent *ent;
    DIR *dir = opendir(path.c_str());

    for (i = 0; i < list_max; i++)
    {
        ent = readdir(dir);
        if (ent == NULL)
            break;

        if (ent->d_type == DT_REG)
        {
            const char *pfile = strrchr(ent->d_name, '.');
            if (pfile != NULL)
            {
                file_path = path + std::string(ent->d_name);

                if (strcasecmp(pfile, ".bmp") == 0)
                {
                    printf("bmp file\n");
                    legal_img = true;
                }
                else if (strcasecmp(pfile, ".jpg") == 0 || strcasecmp(pfile, ".jpeg") == 0)
                {
                    printf("jpg/jpeg file\n");
                    legal_img = true;
                }
                else if (strcasecmp(pfile, ".png") == 0)
                {
                    printf("png file\n");
                    legal_img = true;
                }
            }
        }
        if (legal_img == true)
        {
            legal_img = false;
            imageTable.insert({cnt_r, file_path}); // 将图像索引和文件名插入map
            cnt_r++;
        }

        usleep(50000);
    }

    closedir(dir);

    return cnt_r;
}

static void update_page_img_list(int page)
{
    int tag = (page - 1) * 24;
    int num = imageTable.size() - tag;

    if (num > 24)
        num = 24;

    for (int i = 0; i < num; i++)
    {
        std::string file_path = imageTable[tag + i];
        int w, h, bpp;
        unsigned char *image = NULL;

        const char *pfile = strrchr(file_path.c_str(), '.');
        if (strcasecmp(pfile, ".bmp") == 0)
        {
            printf("bmp file\n");
            image = bmp_image_decode(file_path, w, h, bpp);
        }
        else if (strcasecmp(pfile, ".jpg") == 0 || strcasecmp(pfile, ".jpeg") == 0)
        {
            printf("jpg/jpeg file\n");
            image = jpeg_image_decode(file_path, w, h, bpp);
        }
        else if (strcasecmp(pfile, ".png") == 0)
        {
            printf("png file\n");
            image = png_image_decode(file_path, w, h, bpp);
        }

        if (image != NULL)
        {
            unsigned char *zoomimge = BitImage::BitImageZoom(w, h, image, CELL_W, CELL_H, bpp);
            free(image);

            ui_mutex->lock();
            picture_gui_list_add_img((ImgInfo){CELL_W, CELL_H, zoomimge, bpp}, tag + i);
            ui_mutex->unlock();
        }

        usleep(50000);
    }
}

static unsigned char *bmp_image_decode(std::string &file, int &wight, int &height, int &bit_per_pixel)
{
    BitImage *bmp = new BitImage(file);
    int w = bmp->GetInfo().width;
    int h = bmp->GetInfo().height;
    int bpp = bmp->GetInfo().bpp;

    printf("bmp image width:%d\n", w);
    printf("bmp image height:%d\n", h);
    printf("bmp image bpp:%d\n", bpp);

    unsigned char *buf = (unsigned char *)malloc(w * h * bpp / 8);

    bmp->GetImage(buf, h);

    wight = w;
    height = h;
    bit_per_pixel = bpp;

    delete bmp;

    return buf;
}

static unsigned char *jpeg_image_decode(std::string &file, int &wight, int &height, int &bit_per_pixel)
{
    JpegImage *jpeg = new JpegImage(file);
    int w = jpeg->GetInfo().output_width;
    int h = jpeg->GetInfo().output_height;
    int bpp = jpeg->GetInfo().output_components * 8;

    printf("jpeg image width:%d\n", w);
    printf("jpeg image height:%d\n", h);
    printf("jpeg image bpp:%d\n", bpp);

    unsigned char *buf = (unsigned char *)malloc(w * h * bpp / 8);

    jpeg->GetImage(buf, h);

    wight = w;
    height = h;
    bit_per_pixel = bpp;

    delete jpeg;

    return buf;
}

static unsigned char *png_image_decode(std::string &file, int &wight, int &height, int &bit_per_pixel)
{
    PngImage *png = new PngImage(file);
    int w = png->GetInfo().width;
    int h = png->GetInfo().height;
    int bpp = png->GetInfo().bpp;

    printf("png image width:%d\n", w);
    printf("png image height:%d\n", h);
    printf("png image bpp:%d\n", bpp);

    unsigned char *buf = (unsigned char *)malloc(w * h * bpp / 8);

    png->GetImage(buf, h);

    wight = w;
    height = h;
    bit_per_pixel = bpp;

    delete png;

    return buf;
}

/*
 *@brief 根据索引值获取已知图像数据
 *@param tag 图片索引
 *@param info 保存图像信息
 */
static void get_image(int tag, ImgInfo *info)
{
    std::string path = imageTable[tag];
    unsigned char *image = NULL;

    const char *pfile = strrchr(path.c_str(), '.');
    if (pfile != NULL)
    {
        int w, h, bpp;

        if (strcasecmp(pfile, ".bmp") == 0)
        {
            printf("bmp file\n");
            image = bmp_image_decode(path, w, h, bpp);
        }
        else if (strcasecmp(pfile, ".jpg") == 0 || strcasecmp(pfile, ".jpeg") == 0)
        {
            printf("jpg/jpeg file\n");
            image = jpeg_image_decode(path, w, h, bpp);
        }
        else if (strcasecmp(pfile, ".png") == 0)
        {
            printf("png file\n");
            image = png_image_decode(path, w, h, bpp);
        }

        info->w = w;
        info->h = h;
        info->bpp = bpp;
        info->img_map = image;
    }
}

static int get_next_tag(int now_tag)
{
    int tag = now_tag + 1;

    int img_total = imageTable.size();

    if (tag == img_total)
        tag = 0;

    return tag;
}

static int get_prev_tag(int now_tag)
{
    int tag = now_tag - 1;

    int img_total = imageTable.size();

    if (tag < 0)
        tag = img_total - 1;

    return tag;
}

static void change_img_list_page(int page)
{
    dest_page = page;

    update_mutex.unlock(); // 释放互斥量
}
